package callgraph.process;

import callgraph.domain.JarConfig;
import callgraph.domain.ProfilingFilter;
import callgraph.dto.ClassInterfaceMethodInfo;
import callgraph.enumeration.CallTypeEnum;
import callgraph.util.JavaCGConstants;

import java.io.BufferedWriter;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;

class RecordInterfaceCallClassMethod extends CallGraphProcessor {

    public RecordInterfaceCallClassMethod(CallGraphProcessStorage storage, ProfilingFilter profilingFilter, JarConfig jarConfig, JarFile jarFile, BufferedWriter resultWriter) {
        super(storage, profilingFilter, jarConfig, jarFile, resultWriter);
    }

    @Override
    public boolean handle() {
        if (storage.getClassInterfaceMethodInfoMap().isEmpty() || storage.getInterfaceMethodWithArgsMap().isEmpty()) {
            return true;
        }

        for (Map.Entry<String, ClassInterfaceMethodInfo> classMethodInfo : storage.getClassInterfaceMethodInfoMap().entrySet()) {
            String className = classMethodInfo.getKey();
            ClassInterfaceMethodInfo classInterfaceMethodInfo = classMethodInfo.getValue();
            List<String> interfaceNameList = classInterfaceMethodInfo.getInterfaceNameList();

            // 找到在接口和实现类中都存在的，且有被调用的方法
            for (String interfaceName : interfaceNameList) {
                Set<String> calleeMethodWithArgsSet = storage.getCalleeMethodMapGlobal().get(interfaceName);
                if (calleeMethodWithArgsSet == null) {
                    continue;
                }

                List<String> interfaceMethodWithArgsList = storage.getInterfaceMethodWithArgsMap().get(interfaceName);
                if (interfaceMethodWithArgsList == null || interfaceMethodWithArgsList.isEmpty()) {
                    continue;
                }

                List<String> classMethodWithArgsList = classInterfaceMethodInfo.getMethodWithArgsList();
                for (String classMethodWithArgs : classMethodWithArgsList) {
                    if (!interfaceMethodWithArgsList.contains(classMethodWithArgs) || !calleeMethodWithArgsSet.contains(classMethodWithArgs)) {
                        continue;
                    }

                    String interfaceCallClassMethod = String.format("M:%d %s:%s (%s)%s:%s %d", storage.getCallIdCounter().addAndGet(),
                            interfaceName, classMethodWithArgs,
                            CallTypeEnum.CTE_ITF.getType(), className, classMethodWithArgs, JavaCGConstants.DEFAULT_LINE_NUMBER);
                    // TODO: 2021/11/14 write record
                    writeResult(interfaceCallClassMethod);
                    writeResult(" " + jarNum);
                    writeResult(JavaCGConstants.NEW_LINE);
                }
            }
        }
        return true;

    }

    @Override
    public CallGraphProcessor next() {
        return new RecordMethodAnnotationInfo(storage, profilingFilter, jarConfig, jarFile, resultWriter);
    }
}
